package com.peanut.bosskg.service;

import com.peanut.bosskg.entity.R;
import com.peanut.bosskg.entity.RequestMessageVO;
import com.peanut.bosskg.entity.ResponseMessageVO;
import com.peanut.bosskg.enums.FunCodeEnum;
import com.peanut.bosskg.exception.BizException;
import com.peanut.bosskg.util.DESUtils;
import com.peanut.bosskg.util.JsonUtils;
import com.peanut.bosskg.util.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;

import static com.peanut.bosskg.constant.MerInfoConstant.*;
import static com.peanut.bosskg.constant.YouFuErrorConstant.*;

/**
 * @author peanut
 */
@Slf4j
@Component
public class BaseService {
    @Autowired
    protected RestTemplate restTemplate;

    /**
     * @param funCodeEnum funCode
     * @param requestDTO  请求实体
     * @return applyResult 请求结果
     */
    public <T> ResponseMessageVO applyYouFuByHttpPost(FunCodeEnum funCodeEnum, T requestDTO) {
        log.info("【请求接口】开始:{},{}", funCodeEnum, requestDTO);
        ResponseMessageVO decryptedMsg = new ResponseMessageVO();
        try {
            RequestMessageVO requestMessage = this.buildRequest(funCodeEnum, requestDTO, decryptedMsg);
            ResponseMessageVO encryptedMsg = this.sendToYouFu(requestMessage);
            decryptedMsg = this.handleResponse(encryptedMsg);
        } catch (BizException e) {
            decryptedMsg.setResCode(e.getCode());
            decryptedMsg.setResMsg(e.getMsg());
        } catch (Exception e) {
            log.info("【请求接口】异常:", e);
            decryptedMsg.setResCode(ERROR_6000);
            decryptedMsg.setResMsg(ERROR_MSG_6000);
        }
        log.info("【请求接口】结束:{}", decryptedMsg);
        return decryptedMsg;
    }


    /**
     * 构建请求报文：分为统一请求参数和业务参数两部分
     * 1、DES 加密
     * 2、Base64编码
     * 3、SHA1_WITH_RSA签名
     *
     * @param funCodeEnum funCode
     * @param requestDTO  请求实体参数
     * @return applyResult 请求结果
     */

    public <T> RequestMessageVO buildRequest(FunCodeEnum funCodeEnum, T requestDTO, ResponseMessageVO responseMessage) {
        log.info("【构建请求报文】开始:{},{}", funCodeEnum, requestDTO);
        /**RequestMessageVO:统一请求参数 **/
        RequestMessageVO requestMessage = new RequestMessageVO();
        requestMessage.setReqId(funCodeEnum.getCode() + System.currentTimeMillis());
        requestMessage.setMerId(MER_ID);
        requestMessage.setVersion(API_VERSION);
        requestMessage.setFunCode(funCodeEnum.getCode());
        /**ResponseMessageVO:统一返回参数 **/
        responseMessage.setReqId(requestMessage.getReqId());
        responseMessage.setMerId(MER_ID);
        responseMessage.setVersion(API_VERSION);
        responseMessage.setFunCode(funCodeEnum.getCode());
        /**RequestMessageVO.setReqData:业务请求参数 **/
        String reqData = JsonUtils.toJson(requestDTO);
        /**1、DES 加密**/
        byte[] bs;
        try {
            bs = DESUtils.encrypt(reqData.getBytes(CHARSET_UTF_8), INTER_KEY);
        } catch (UnsupportedEncodingException e) {
            log.error("【构建请求报文】不支持的字符集，", e);
            throw new BizException("不支持的字符集");
        } catch (Exception e) {
            log.error("【构建请求报文】加密异常，", e);
            throw new BizException("加密异常");
        }

        /**
         * 2、Base64编码
         **/
        String reqDataEncrypt = Base64Utils.encodeToString(bs);
        requestMessage.setReqData(reqDataEncrypt);
        /**3、SHA1_WITH_RSA签名**/
        try {
            requestMessage.setSign(RSAUtils.sign(reqDataEncrypt, MER_PRIVATE_KEY));
        } catch (Exception e) {
            log.error("【构建请求报文】签名异常=", e);
            throw new BizException("【构建请求报文】签名异常");
        }
        log.info("【构建请求报文】结束:{}", requestMessage);
        return requestMessage;
    }

    /**
     * 向优付发出HttpPost申请
     *
     * @param requestMessage
     * @return String
     */
    public ResponseMessageVO sendToYouFu(RequestMessageVO requestMessage) {
        log.info("【HTTP请求报文】{}", requestMessage);
        ResponseEntity<ResponseMessageVO> responseEntity = restTemplate.postForEntity(YOU_FU_URL, requestMessage, ResponseMessageVO.class);
        HttpStatus statusCode = responseEntity.getStatusCode();
        int statusCodeValue = responseEntity.getStatusCodeValue();
        if (HttpStatus.OK != statusCode) {
            throw new BizException("HTTP请求失败,HttpStatusCode" + statusCodeValue);
        }
        ResponseMessageVO responseMessage = responseEntity.getBody();
        if (ObjectUtils.isEmpty(responseMessage)) {
            throw new BizException("HTTP请求返回结果为空,HttpStatusCode" + statusCodeValue);
        }
        log.info("【HTTP返回报文】ResData{}", responseMessage);
        return responseMessage;
    }

    /**
     * HTTP响应结果处理：得到明文
     * 1、SHA1_WITH_RSA验签
     * 2、Base64解编码
     * 3、DES 解密
     *
     * @param responseMessage
     * @return
     */
    public ResponseMessageVO handleResponse(ResponseMessageVO responseMessage) {
        log.info("【HTTP响应结果处理】开始:{}", responseMessage);
        String resCode = responseMessage.getResCode();
        String resMsg = responseMessage.getResMsg();
        if (!SUCCESS.equals(resCode)) {
            log.info("【HTTP响应结果处理】响应结果异常");
            if (StringUtils.isBlank(resCode)) {
                resCode = ERROR_6000;
                resMsg = "【HTTP响应结果处理】响应结果异常";
            }
            if (StringUtils.isBlank(resMsg)) {
                resMsg = "【HTTP响应结果处理】响应结果异常";
            }
            throw new BizException(resCode, resMsg);
        }
        String resData = responseMessage.getResData();
        if (StringUtils.isBlank(resData)) {
            log.error("【HTTP响应结果处理】返回结果为空");
            throw new BizException("【HTTP响应结果处理】返回结果为空");
        }
        String sign = responseMessage.getSign();
        if (StringUtils.isBlank(sign)) {
            log.error("【HTTP响应结果处理】签名为空");
            throw new BizException("【HTTP响应结果处理】签名为空");
        }
        boolean isVerifySuccess;
        /** 1、SHA1_WITH_RSA验签 **/
        try {
            isVerifySuccess = RSAUtils.verify(resData, sign, YOU_FU_PUBLIC_KEY);
        } catch (Exception e) {
            log.error("【HTTP响应结果处理】验签异常=", e);
            throw new BizException("【HTTP响应结果处理】验签异常");
        }
        if (!isVerifySuccess) {
            log.error("【HTTP响应结果处理】验签失败");
            throw new BizException("【HTTP响应结果处理】验签失败");
        }
        /** 2、Base64解编码 **/
        byte[] base64bs = Base64Utils.decode(resData.getBytes());
        /** 3、DES 解密 **/
        String resultData = null;
        try {
            resultData = DESUtils.decryptToString(base64bs, INTER_KEY);
        } catch (Exception e) {
            log.error("【HTTP响应结果处理】DES解密异常=", e);
            throw new BizException("【HTTP响应结果处理】DES解密异常");
        }
        responseMessage.setSign(null);
        responseMessage.setResData(resultData);
        log.info("【HTTP响应结果处理】结束:{}", responseMessage);
        return responseMessage;
    }

    /**
     * 构造返回结果
     *
     * @param responseMessage
     * @return
     */
    public R buildResult(ResponseMessageVO responseMessage) {
        log.info("【构造返回结果】开始:{}", responseMessage);
        R r = new R(responseMessage.getResCode(), responseMessage.getResMsg(), responseMessage.getResData());
        log.info("【构造返回结果】结束:{}", responseMessage);
        return r;
    }
}
